from sys import argv
from PyQt5 import QtGui
from PyQt5.QtCore import QObject, QSize, QThread
from PyQt5.QtWidgets import (
    QApplication,
    QWidget,
    QVBoxLayout,
    QPushButton,
    QListWidget,
    QHBoxLayout,
    QLineEdit,
    QListWidgetItem,
    QFileDialog,
    QMessageBox,
)
import os
import subprocess


class AdbTools(QObject):
    # https://www.endpoint.com/blog/2015/01/getting-realtime-output-using-python/
    ADB_PATH = "adb"

    def adbdevices(self, adbpath=ADB_PATH):
        return set(
            [
                device.split("\t")[0]
                for device in subprocess.check_output([adbpath, "devices"])
                .decode("UTF-8")
                .splitlines()
                if device.endswith("\tdevice")
            ]
        )

    def adbshell(self, command, serial=None, adbpath=ADB_PATH):
        args = [adbpath]
        if serial is not None:
            args.extend(["-s", serial])
        args.extend(["shell", command])
        return subprocess.check_output(args)

    def adbpull(self, src, target, series=None, adbpath=ADB_PATH):
        args = [adbpath]
        if series is not None:
            args.extend(["-s", series])
        args.extend(["pull", "-p", src, target])
        print(args)
        # return subprocess.check_output(args)
        # self.run_command(" ".join(args))
        self.run_command(args)

    def run_command(self, command):
        process = subprocess.Popen(
            command, stdout=subprocess.PIPE, encoding="utf8", shell=True
        )
        while True:
            output = process.stdout.readline().strip()
            if output == "" and process.poll() is not None:
                break
            if output:
                print(output)
        rc = process.poll()
        return rc


class PullLog(QObject):
    def __init__(self, path, series):
        super().__init__()
        self.targetPath = path
        self.series = series
        self.adb = AdbTools()

    def pull(self):
        self.adb.adbpull("/vendor/etc/", self.targetPath, series=self.series)


class ItemWidget(QWidget):
    def __init__(self, item, series=None, phone=None, type=None, *args, **kwargs):
        super(ItemWidget, self).__init__(*args, **kwargs)
        self._item = item  # 保留list item的对象引用
        self.targetPath = ""
        self.series = series
        self.pullThread = QThread(self)

        # UI
        layout = QHBoxLayout(self)
        self.setLayout(layout)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(QLineEdit(series, self))

        self.phone = QLineEdit("phone", self)
        layout.addWidget(self.phone)

        self.chip_type = QLineEdit("chip_type", self)
        layout.addWidget(self.chip_type)
        layout.addWidget(QPushButton("Select Path", self, clicked=self.onSelectPath))
        layout.addWidget(QPushButton("Pull log", self, clicked=self.onPullLog))
        layout.addWidget(QPushButton("Stop Pull", self, clicked=self.onStopPullLog))
        layout.addWidget(QPushButton("clean log", self, clicked=self.onClearLog))

    def onSelectPath(self):
        print("on_select_path")
        dir = QFileDialog.getExistingDirectory(self, "选取文件夹", os.getcwd())
        if dir == "":
            return

        print("\n你选择的文件夹为:" + dir)
        self.targetPath = dir

    def onPullLog(self):
        print("onPullLog")
        if self.targetPath == "":
            QMessageBox.information(self, "提示", "目标文件夹为空")
            return

        if not os.path.isdir(self.targetPath):
            QMessageBox.information(self, "提示", "目标文件夹：%s 无效" % self.targetPath)
            return

        self.pullWorker = PullLog(self.targetPath, self.series)
        self.pullWorker.moveToThread(self.pullThread)  # 移动到线程中执行
        self.pullThread.started.connect(self.pullWorker.pull)
        self.pullThread.start()

    def onStopPullLog(self):
        if self.pullThread and self.pullThread.isRunning():
            self.pullThread.quit()

    def onClearLog(self):
        print("onClearLog")

    def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
        self.onStopPullLog()
        return super().closeEvent(a0)


class PullLogWindow(QWidget):
    def __init__(self, parent=None) -> None:
        super().__init__(parent=parent)

        self.adb = AdbTools()
        self.series_widget_dict = dict()

        layout = QVBoxLayout()
        self.setLayout(layout)

        layout.addWidget(
            QPushButton("刷新连接手机列表", self, clicked=self.on_fresh_link_phone)
        )

        self.phone_view_list = QListWidget(self)
        layout.addWidget(self.phone_view_list)
        self.phone_view_list.setSpacing(3)

        self.resize(1000, 300)

    def on_add_item_view(self, series):
        item = QListWidgetItem(self.phone_view_list)
        widget = ItemWidget(item, series)
        item.setSizeHint(widget.sizeHint())
        self.series_widget_dict[series] = item
        self.phone_view_list.setItemWidget(item, widget)

    def on_delete_item_view(self, o):
        item = self.series_widget_dict[o]
        row = self.phone_view_list.indexFromItem(item).row()
        self.phone_view_list.itemWidget(item).close()
        self.phone_view_list.takeItem(row)
        self.phone_view_list.removeItemWidget(item)
        self.series_widget_dict.pop(o)

    def on_fresh_link_phone(self):
        new_list = self.adb.adbdevices()
        for n in new_list:
            if n not in self.series_widget_dict.keys():
                self.on_add_item_view(n)
        for o in list(self.series_widget_dict.keys()):
            if o not in new_list:
                self.on_delete_item_view(o)
        print(self.series_widget_dict)

    def clearItems(self):
        # 清空所有Item
        for _ in range(self.phone_view_list.count()):
            self.phone_view_list.itemWidget(self.phone_view_list.item(0)).close()
            self.phone_view_list.takeItem(0)

    def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
        self.clearItems()
        return super().closeEvent(a0)


if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)
    w = PullLogWindow()
    w.show()
    sys.exit(app.exec_())
